package com.demo.config.apache.util;

import com.demo.config.apache.temporary.PDFReader;
import org.apache.pdfbox.Loader;
import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.pdmodel.*;
import org.apache.pdfbox.pdmodel.font.PDFont;
import org.apache.pdfbox.pdmodel.font.PDTrueTypeFont;
import org.apache.pdfbox.pdmodel.font.PDType0Font;
import org.apache.pdfbox.pdmodel.font.PDType1Font;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
import org.apache.pdfbox.pdmodel.interactive.documentnavigation.outline.PDDocumentOutline;
import org.apache.pdfbox.pdmodel.interactive.documentnavigation.outline.PDOutlineItem;
import org.apache.pdfbox.text.PDFTextStripper;
import org.apache.pdfbox.text.PDFTextStripperByArea;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Iterator;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * PDF文档功能： ⅰ. 获取纲要 ⅱ. 获取所有标题包含子标题 ⅲ. 打印字体样式 ⅳ. 分页获取文字的内容 ⅴ. 指定区域提取文本-第几页什么区域 ⅵ.
 * 分页读取文本-开始页面、结束页面 ⅶ. 提取图片
 *
 * @author wgr
 */
public class PDFUtil {

	static String fileName = "D:\\file\\pdf\\testPdf.pdf";

	// =================================================第一部分=========================================================
	/**
	 * 打印纲要、每一层级标题、字体样式
	 */
	public static void getPdfOutline() {
		try {
			// 打开pdf文件流
			File fdf = new File(fileName);
			// 加载 pdf 文档,获取PDDocument文档对象
			PDDocument document = Loader.loadPDF(fdf);
			// 打印字体样式
			PDPageTree pages = document.getPages();
			for (PDPage page : pages) {
				PDResources resources = page.getResources();
				// 遍历资源并查询字体样式
				for (COSName fontName : resources.getFontNames()) {
					PDFont font = resources.getFont(fontName);
					if (font instanceof PDTrueTypeFont trueTypeFont) {
						System.out.println("字体名称： " + trueTypeFont.getName());
						System.out.println("字体样式： " + trueTypeFont.getFontDescriptor().getFontName());
					}
					else if (font instanceof PDType1Font type1Font) {
						System.out.println("字体名称： " + type1Font.getName());
						System.out.println("字体是否加粗：" + type1Font.getFontDescriptor().getFontWeight());
					}
					else if (font instanceof PDType0Font type0Font) {
						// 宋体
						System.out.println("字体名称： " + type0Font.getName());
						System.out.println("字体是否加粗：" + type0Font.getFontDescriptor().getFontWeight());
					}
					else {
						// 字体名称
						System.out.println(font.getName());
					}
				}
			}
			// 获取PDDocumentCatalog文档目录对象
			PDDocumentCatalog catalog = document.getDocumentCatalog();
			// 获取PDDocumentOutline文档纲要对象
			PDDocumentOutline outline = catalog.getDocumentOutline();
			// 获取第一个纲要条目（标题1）
			PDOutlineItem item = outline.getFirstChild();
			// 遍历每一个标题1
			while (item != null) {
				// 打印标题1的文本
				System.out.println("Item:" + item.getTitle());
				// 获取标题1下的第一个子标题（标题2）
				PDOutlineItem child = item.getFirstChild();
				// 遍历每一个标题2
				while (child != null) {
					// 打印标题2的文本
					System.out.println("    Child:" + child.getTitle());
					// 指向下一个标题2
					child = child.getNextSibling();
				}
				// 指向下一个标题1
				item = item.getNextSibling();
			}
			// 关闭输入流
			document.close();
		}
		catch (IOException ex) {
			Logger.getLogger(PDFReader.class.getName()).log(Level.SEVERE, null, ex);
		}
	}

	/**
	 * 打印一级目录
	 */
	public static void getPdfCatalog() {
		try {
			// 打开pdf文件流
			File fdf = new File(fileName);
			// 加载 pdf 文档,获取PDDocument文档对象
			PDDocument document = Loader.loadPDF(fdf);
			// 获取PDDocumentCatalog文档目录对象
			PDDocumentCatalog catalog = document.getDocumentCatalog();
			// 获取PDDocumentOutline文档纲要对象
			PDDocumentOutline outline = catalog.getDocumentOutline();
			// 获取第一个纲要条目（标题1）
			if (outline != null) {
				PDOutlineItem item = outline.getFirstChild();
				// 遍历每一个标题1
				while (item != null) {
					// 打印标题1的文本
					System.out.println("Item:" + item.getTitle());
					// 指向下一个标题1
					item = item.getNextSibling();
				}
			}
			// 关闭输入流
			document.close();
		}
		catch (IOException ex) {
			Logger.getLogger(PDFReader.class.getName()).log(Level.SEVERE, null, ex);
		}
	}

	/**
	 * 获取PDF文档元数据
	 */
	public static void getPdfInformation() {
		try {
			// 打开pdf文件流
			File fdf = new File(fileName);
			// 加载 pdf 文档,获取PDDocument文档对象
			PDDocument document = Loader.loadPDF(fdf);
			// 文档属性信息
			PDDocumentInformation info = document.getDocumentInformation();

			System.out.println("页数:" + document.getNumberOfPages());

			System.out.println("标题:" + info.getTitle());
			System.out.println("主题:" + info.getSubject());
			System.out.println("作者:" + info.getAuthor());
			System.out.println("关键字:" + info.getKeywords());

			System.out.println("应用程序:" + info.getCreator());
			System.out.println("pdf 制作程序:" + info.getProducer());

			System.out.println("Trapped:" + info.getTrapped());

			System.out.println("创建时间:" + dateFormat(info.getCreationDate()));
			System.out.println("修改时间:" + dateFormat(info.getModificationDate()));

			// 关闭输入流
			document.close();
		}
		catch (IOException ex) {
			Logger.getLogger(PDFReader.class.getName()).log(Level.SEVERE, null, ex);
		}
	}

	/**
	 * 分页获取文字的内容
	 *
	 */
	public static void readPage() throws Exception {
		File file = new File(fileName);
		PDDocument doc = Loader.loadPDF(file);
		PDFTextStripper textStripper = new PDFTextStripper();
		for (int i = 1; i <= doc.getNumberOfPages(); i++) {
			textStripper.setStartPage(i);
			textStripper.setEndPage(i);
			// 一次输出多个页时，按顺序输出
			textStripper.setSortByPosition(true);
			String s = textStripper.getText(doc);
			System.out.println("当前页：" + i);
			System.out.println("输出内容：");
			System.out.println(s);
		}
		doc.close();
	}

	/**
	 * 区域解析 指定区域提取文本
	 *
	 */
	public static void readRectangle() throws Exception {
		String filePath = fileName;
		File file = new File(filePath);
		PDDocument doc = Loader.loadPDF(file);
		// 这个四边形所在区域在 y轴向下为正，x轴向右为正。
		int x = 35;
		int y = 500;
		int width = 500;
		int height = 500;
		PDFTextStripperByArea stripper = new PDFTextStripperByArea();
		stripper.setSortByPosition(true);
		// 划定区域
		Rectangle2D rect = new Rectangle(x, y, width, height);
		stripper.addRegion("area", rect);
		PDPage page = doc.getPage(1);
		stripper.extractRegions(page);
		// 获取区域的text
		String data = stripper.getTextForRegion("area");
		data = data.trim();
		System.out.println(data);
		doc.close();
	}

	/**
	 * 提取文本
	 */
	public static void extractText(String path) {
		try {
			File fdf = new File(path);
			// 通过文件名加载文档
			PDDocument pdd = Loader.loadPDF(fdf);
			// 获取文档的页数
			int pageNumber = pdd.getNumberOfPages();
			// 剥离器（读取pdf文件）
			PDFTextStripper stripper = new PDFTextStripper();
			// 排序
			stripper.setSortByPosition(true);
			// 设置要读取的起始页码
			stripper.setStartPage(1);
			// 设置要读取的结束页码
			stripper.setEndPage(pageNumber);

			// 全部内容
			String text = stripper.getText(pdd);
			// System.out.println(text);
			// =================================================
			// 生成的txt的文件路径
			// String docPath =path.substring(0,path.lastIndexOf("."))+".txt";
			// File doc = new File(docPath);
			// if(!doc.exists()){
			// doc.createNewFile();
			// }
			// 文件输出流
			// FileOutputStream fos = new FileOutputStream(doc);
			// Writer writer = new OutputStreamWriter(fos, "utf-8");
			// stripper.writeText(pdd, writer);
			// writer.close();
			// fos.close();
			// =================================================

			System.out.println("提取文本完成");
			pdd.close();
		}
		catch (Exception e) {
			Logger.getLogger(PDFReader.class.getName()).log(Level.SEVERE, null, e);
		}
	}

	/**
	 * 提取图片
	 */
	public static boolean extractImages(String path) {
		boolean result = true;
		try {
			File fdf = new File(path);
			// 通过文件名加载文档
			PDDocument document = Loader.loadPDF(fdf);
			PDPageTree pages = document.getPages();
			Iterator<PDPage> iter = pages.iterator();
			// 生成的txt的文件路径
			String imagePath = path.substring(0, path.lastIndexOf("."));
			while (iter.hasNext()) {
				PDPage page = iter.next();
				PDResources resources = page.getResources();
				resources.getXObjectNames().forEach(e -> {
					try {
						if (resources.isImageXObject(e)) {
							PDImageXObject imageXobject = (PDImageXObject) resources.getXObject(e);
							BufferedImage bufferedImage = imageXobject.getImage();
							System.out.println(bufferedImage);
							ImageIO.write(bufferedImage, "jpg", new File(imagePath + "_" + e + ".jpg"));
						}

					}
					catch (IOException ioException) {
						Logger.getLogger(PDFReader.class.getName()).log(Level.SEVERE, null, ioException);
					}
				});
			}
			System.out.println("提取图片完成");
			// document.save(fdf);
			document.close();
		}
		catch (IOException ex) {
			Logger.getLogger(PDFReader.class.getName()).log(Level.SEVERE, null, ex);
			return false;
		}
		return result;
	}

	/**
	 * 获取格式化后的时间信息
	 * @param calendar 时间信息
	 */
	public static String dateFormat(Calendar calendar) {
		if (null == calendar)
			return null;
		String date = null;
		String pattern = "yyyy-MM-dd HH:mm:ss";
		SimpleDateFormat format = new SimpleDateFormat(pattern);
		date = format.format(calendar.getTime());
		return date;
	}

	// =================================================第二部分=========================================================

	/**
	 * 获取纲要
	 */
	public static String getPdfEssentials(PDDocument document) {
		StringBuilder itemChild = new StringBuilder();

		try {
			// 获取PDDocumentCatalog文档目录对象
			PDDocumentCatalog catalog = document.getDocumentCatalog();
			// 获取PDDocumentOutline文档纲要对象
			PDDocumentOutline outline = catalog.getDocumentOutline();
			// 获取第一个纲要条目（标题1）
			PDOutlineItem item = outline.getFirstChild();
			// 获取当前标题下的所有子集
			getItemChild(item, itemChild);
			// 关闭输入流
			document.close();
		}
		catch (IOException ex) {
			Logger.getLogger(PDFReader.class.getName()).log(Level.SEVERE, null, ex);
		}
		return itemChild.toString();
	}

	/**
	 * 获取所有子标题
	 * @param item 标题1
	 * @param itemChild 返回数据
	 */
	private static void getItemChild(PDOutlineItem item, StringBuilder itemChild) {

		while (item != null) {
			// 打印标题1的文本
			itemChild.append(item.getTitle());
			System.out.println(item.getTitle());
			// 获取标题1下的第一个子标题（标题2）
			PDOutlineItem child = item.getFirstChild();
			// 获取所有子集
			getItemChild(child, itemChild);
			// 指向下一个标题1
			item = item.getNextSibling();
		}
	}

	/**
	 * 打印字体样式
	 */
	public static void getPdfFontStyle(PDDocument document) {
		try {
			// 打印字体样式
			PDPageTree pages = document.getPages();
			for (PDPage page : pages) {
				PDResources resources = page.getResources();
				// 遍历资源并查询字体样式
				for (COSName fontName : resources.getFontNames()) {
					PDFont font = resources.getFont(fontName);
					String name = font.getName();
				}
			}
			// 关闭输入流
			document.close();
		}
		catch (IOException ex) {
			Logger.getLogger(PDFReader.class.getName()).log(Level.SEVERE, null, ex);
		}
	}

	/**
	 * 分页获取文字的内容
	 * @param doc doc
	 * @param pageIndex 第几页
	 * @return 当前文本
	 */
	public static String getText(PDDocument doc, int pageIndex) throws Exception {
		StringBuilder text = new StringBuilder();
		PDFTextStripper textStripper = new PDFTextStripper();
		for (int i = 1; i <= doc.getNumberOfPages(); i++) {
			if (pageIndex > 0 && i == pageIndex) {
				textStripper.setStartPage(i);
				textStripper.setEndPage(i);
				// 一次输出多个页时，按顺序输出
				textStripper.setSortByPosition(true);
				return checkText(textStripper.getText(doc));
			}
			else if (pageIndex == 0) {
				textStripper.setStartPage(i);
				textStripper.setEndPage(i);
				// 一次输出多个页时，按顺序输出
				textStripper.setSortByPosition(true);
				String text1 = checkText(textStripper.getText(doc));
				// 判断是否只包含数字--行号
				if (matchesNum(text1)) {
					text.append(text1);
				}
			}
			else {
				break;
			}
		}
		doc.close();
		return text.toString();
	}

	/**
	 * 区域解析 指定区域提取文本
	 * @param doc doc
	 * @param pageIndex 第几页 这个四边形所在区域在
	 * @param x x轴向右为正 30
	 * @param y y轴向下为正 500
	 * @param width 宽 500
	 * @param height 高 500
	 */
	public static String readRectangle(PDDocument doc, int pageIndex, int x, int y, int width, int height)
			throws Exception {
		PDFTextStripperByArea stripper = new PDFTextStripperByArea();
		stripper.setSortByPosition(true);
		// 划定区域
		Rectangle2D rect = new Rectangle(x, y, width, height);
		stripper.addRegion("area", rect);
		PDPage page = doc.getPage(pageIndex);
		stripper.extractRegions(page);
		// 获取区域的text
		String data = checkText(stripper.getTextForRegion("area"));
		return data;
	}

	/**
	 * 分页读取文本
	 * @param pdd 文档
	 * @param startPage 开始页
	 * @param endPage 结束页
	 */
	public static String getPdfText(PDDocument pdd, int startPage, int endPage) throws IOException {
		// 获取文档的页数
		int pageNumber = pdd.getNumberOfPages();
		// 剥离器（读取pdf文件）
		PDFTextStripper stripper = new PDFTextStripper();
		// 排序
		stripper.setSortByPosition(true);
		// 设置要读取的起始页码
		stripper.setStartPage(startPage == 0 ? 1 : startPage);
		// 设置要读取的结束页码
		if (endPage > startPage && endPage <= pageNumber) {
			pageNumber = endPage;
		}
		stripper.setEndPage(pageNumber);
		// 全部内容
		return checkText(stripper.getText(pdd));
	}

	/**
	 * 提取图片
	 */
	public static boolean getPdfImages(PDDocument document, String imagePath) {
		boolean result = true;
		try {
			PDPageTree pages = document.getPages();
			Iterator<PDPage> iter = pages.iterator();
			while (iter.hasNext()) {
				PDPage page = iter.next();
				PDResources resources = page.getResources();
				resources.getXObjectNames().forEach(e -> {
					try {
						if (resources.isImageXObject(e)) {
							PDImageXObject imageXobject = (PDImageXObject) resources.getXObject(e);
							BufferedImage bufferedImage = imageXobject.getImage();
							ImageIO.write(bufferedImage, "png", new File(imagePath + "\\" + e + ".png"));
						}

					}
					catch (IOException ioException) {
						Logger.getLogger(PDFReader.class.getName()).log(Level.SEVERE, null, ioException);
					}
				});
			}
			document.close();
		}
		catch (IOException ex) {
			Logger.getLogger(PDFReader.class.getName()).log(Level.SEVERE, null, ex);
			return false;
		}
		return result;
	}

	// 校验是否只包含数字--行号 是：false
	private static boolean matchesNum(String text1) {
		return !text1.trim().matches("\\d+");
	}

	/**
	 * 针对特殊字符进行解析，可以打印出来
	 * @param allText 文本
	 * @return 变异后的文本
	 */
	static String checkText(String allText) {
		// 获取所有文本
		allText = allText.replaceAll("\\t", " "); // 替换制表符为空格
		allText = allText.replaceAll("\\n", " "); // 替换换行符为换行
		allText = allText.replaceAll("\\r", " "); // 替换回车符为空字符
		allText = allText.replaceAll("\f", " "); // 替换特殊字符为空字符
		allText = allText.replaceAll("\u0001", ""); // 替换特殊字符为空字符
		allText = allText.replaceAll("\ufffd", ""); // 替换特殊字符为空字符
		allText = allText.replaceAll("\u0001", ""); // 替换特殊字符为空字符
		allText = allText.replaceAll("\u0000", ""); // 替换特殊字符为空字符
		allText = allText.replaceAll("\u0000", ""); // 替换特殊字符为空字符
		allText = allText.replaceAll("\u0000", ""); // 替换特殊字符为空字符
		allText = allText.replaceAll("\u0001", ""); // 替换特殊字符为空字符
		allText = allText.replaceAll("\ufffd", ""); // 替换特殊字符为空字符
		allText = allText.replaceAll("\u000E", ""); // 替换特殊字符为空字符
		allText = allText.replaceAll("\\p{Z}", " "); // 替换所有其他不可打印字符为空字符

		return allText;

	}

}
